using System;
using System.Collections.Generic;
using C3.XNA;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using SomeGame.Actors.Types;
using SomeGame.GUI;
using SomeGame.Input;
using SomeGame.Tools;
using SomeGame.Zones;

namespace SomeGame {

    public class GameEngine : Game {

        public static GraphicsDeviceManager GraphicsDeviceManager;
        public static SpriteBatch SpriteBatch;
        public static Rectangle GameBounds;
        public static Vector2 GameBoundsPositionInWorldCoords;
        public static ContentManager ContentManager;
        public static Action ExitGame;
        public static Camera Camera;
        public static Matrix CameraTransformation;
        public static Player Player;
        // Textures.
        public static Texture2D Blank;
        // TODO: have ScreenManager load it's own content? Have Screens load their own and unload?
        // SpriteFonts.
        public static SpriteFont Consolas16;
        // Keyboard.
        public static KeyboardState KeyboardState;
        public static KeyboardState PreviousKeyboardState;
        public static Keys[] PressedKeys;
        public static Keys[] PreviousPressedKeys = new Keys[0];
        public static IList<char> WindowsCharsEntered = new List<char>();
        public static IList<char> PreviousWindowsCharsEntered = new List<char>();
        // Mouse.
        public static MouseState MouseState;
        public static MouseState PreviousMouseState;
        public static Point MousePoint;
        public static Point PreviousMousePoint;
        // Misc.
        private static bool isPaused;
        public static bool IsPaused {
            get { return isPaused; }
            set {
                isPaused = value;
                if (isPaused) {
                    MediaPlayer.Pause();
                } else {
                    MediaPlayer.Resume();
                }
            }
        }
	    public static readonly Random Random = new Random();

        public GameEngine() {
            GraphicsDeviceManager = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            ContentManager = Content;
            IsMouseVisible = true;
        }

        protected override void LoadContent() {
            SpriteBatch = new SpriteBatch(GraphicsDevice);
            // TODO: have ScreenManager load it's own content? Have Screens load their own and unload?
            Blank = ContentManager.Load<Texture2D>(@"Images\Blank");
            Consolas16 = Content.Load<SpriteFont>(@"Fonts\Consolas16");
            Configure();
        }

        private void Configure() {
            GameBounds = GraphicsHelper.SetScreenTo720P(GraphicsDeviceManager);
            ScreenManager.ActivateScreen(ScreenManager.BACKGROUND_SCREEN);
            ScreenManager.ActivateScreen(ScreenManager.MAIN_MENU_SCREEN);
            // Map Pressed Once Keys
            InputManager.MapPressedOnceKey(Keys.Escape, InputActions.Exit);
            // Map Pressed Continually Keys
            InputManager.MapPressedContinuallyKey(Keys.A, InputActions.PlayerWalkLeft);
            InputManager.MapPressedContinuallyKey(Keys.D, InputActions.PlayerWalkRight);
            InputManager.MapPressedContinuallyKey(Keys.E, InputActions.PlayerAttack);
            InputManager.MapPressedContinuallyKey(Keys.F, InputActions.ToggleFullScreen);
            // Map Released Keys
            InputManager.MapReleasedKey(Keys.A, InputActions.PlayerStopWalking);
            InputManager.MapReleasedKey(Keys.D, InputActions.PlayerStopWalking);
            InputManager.MapReleasedKey(Keys.E, InputActions.PlayerStopAttack);
            EventInput.Initialize(Window);
            EventInput.CharEntered += (sender, args) => WindowsCharsEntered.Add(args.Character);
            Camera = new Camera(GameBounds);
            ExitGame = Exit;
        }

        protected override void Update(GameTime gameTime) {

            /*
             * Handling the Keyboard and Mouse old/new here, 
             * wrapping the Subsystems, keeps the entire game
             * informed of changes.
             */

            //-----( Current State )-------------

            // Keyboard.
            KeyboardState = Keyboard.GetState();
            PressedKeys = KeyboardState.GetPressedKeys();
            // Mouse.
            MouseState = Mouse.GetState();
            CameraTransformation = Camera.GetTransformation();
            // GameBounds loction in world position.
            GameBoundsPositionInWorldCoords = Vector2.Transform(new Vector2(GameBounds.X, GameBounds.Y),
                Matrix.Invert(CameraTransformation));
            // Screen position to world position for mouse.
            Vector2 worldMousePosition = Vector2.Transform(new Vector2(MouseState.X, MouseState.Y),
                Matrix.Invert(CameraTransformation));
            MousePoint = new Point((int) worldMousePosition.X, (int) worldMousePosition.Y);

            //-----( Subsystems )----------------

            // Update Subsystems.
            InputManager.Update(gameTime);
            ScreenManager.Update(gameTime);

            //-----( Previous State )------------

            // Keyboard.
            PreviousKeyboardState = KeyboardState;
            PreviousPressedKeys = PressedKeys;
            PreviousWindowsCharsEntered = WindowsCharsEntered;
            WindowsCharsEntered = new List<char>();
            // Mouse.
            PreviousMouseState = MouseState;
            PreviousMousePoint = MousePoint;

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime) {
            GraphicsDevice.Clear(Color.Black);
            if (Camera.Mode == CameraMode.Menu) {
                SpriteBatch.Begin();
            } else { // CameraMode.Play.
                SpriteBatch.Begin(SpriteSortMode.Deferred,
                    BlendState.AlphaBlend,
                    null,
                    null,
                    null, 
                    null,
                    CameraTransformation);
            }
            ScreenManager.Draw();
            DebugHelper.Draw();
            Rectangle topBar = new Rectangle(0, 0, GameBounds.Width, GameBounds.Top);
            Rectangle bottomBar = new Rectangle(0,
                GameBounds.Bottom,
                GameBounds.Width,
                GraphicsDevice.Viewport.Height-GameBounds.Bottom);
            SpriteBatch.Draw(Blank, topBar, Color.Black);
            SpriteBatch.Draw(Blank, bottomBar, Color.Black);
            SpriteBatch.End();
            base.Draw(gameTime);
        }

    }

}